/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include "dataTools.h"
#include "controller.h"
#include "graph.h"
#include <assert.h>
#include <sstream>
using namespace std;


class ExportEdgeTool:public AnalysisTool {
public:
	ExportEdgeTool(Controller *controller):AnalysisTool("Data","Export Edges",controller) {
		setPropertyString("File", "");
		setPropertyStringList("Property", "", "edge", true);
		setPropertyStringList("Node Filter", "", "node");
		setPropertyStringList("Edge Filter", "", "edge");
	}
	void compute() {
		assert(controller);
		Graph *graph = controller->getGraph("graph");
		string file = getPropertyString("File");
		string nodeFilterProperty = PROPERTY(getPropertyString("Node Filter"));
		string edgeFilterProperty = PROPERTY(getPropertyString("Edge Filter"));
		string props = getPropertyString("Property");
		istringstream iss(props);
		string token;
		vector<string> properties;
		while(getline(iss, token, ':')) {
			if(token.length()>0) {
				properties.push_back(token);
			}
		}
		if(listener) listener->setProgress(0);

		
		
		ofstream outp(file.c_str());
		if(!outp.is_open()) {
			error("Cannot open file %s\n", file.c_str());
			return;
		} 
		bool printedHeader = false;
		ElementIterator *it = graph->createEdgeIterator();
		for(it->begin();it->hasMoreElements();) {
			Edge *edge = (Edge*) it->next();
			string line = "";
			string lineHeader = "";
			string lineHeaderType = "";
			
			Node  *src = edge->getNode0();
			Node  *dst = edge->getNode1();
			bool passFilterSrc = graph->getAsBoolean(src, nodeFilterProperty);
			bool passFilterDst = graph->getAsBoolean(dst, nodeFilterProperty);
			if(!passFilterSrc) continue;
			if(!passFilterDst) continue;
			
			bool passFilterEdge = graph->getAsBoolean(edge, edgeFilterProperty);
			if(!passFilterEdge) continue;
			
			if(!printedHeader) {
				lineHeaderType = "";//INT\tINT\t";
				lineHeader = "";//From\tTo\t";
			}
			for(unsigned j=0;j<properties.size();j++) {
				int type = edge->getPropertyType(properties[j]);
				string sValue = edge->getAsString(properties[j]);
				if(!printedHeader) {
					string sType = "STRING";
					if(type==PROPERTY_FLOAT) sType = "FLOAT";
					if(type==PROPERTY_SIGNED) sType = "SIGNED";
					if(type==PROPERTY_INT) sType = "INT";
					if(type==PROPERTY_STRING) sType = "STRING";
					if(type==PROPERTY_BOOL) sType = "BOOL";
					lineHeaderType = lineHeaderType + sType;
					lineHeader = lineHeader + properties[j];
					if(j<properties.size()-1) {
						lineHeaderType += "\t";
						lineHeader += "\t";
					}
				}
				line = line +  sValue;
				if(j<properties.size()-1) {
					line += "\t";
				}
			}
			if(!printedHeader) {
				outp << lineHeaderType << endl;
				outp << lineHeader << endl;
				printedHeader = true;
			}
			outp << line << endl;
		}
		outp.close();	
		graph->destroyIterator(it);
		
		
		if(listener) listener->done();
	}
};
class ExportTool:public AnalysisTool {
public:
	ExportTool(Controller *controller):AnalysisTool("Data","Export Nodes",controller) {
		setPropertyString("File", "");
		setPropertyStringList("Property", "", "node", true);
		setPropertyStringList("Node Filter", "", "node");
	}
	void compute() {
		assert(controller);
		Graph *graph = controller->getGraph("graph");
		string file = getPropertyString("File");
		string props = getPropertyString("Property");
		string filterProperty = PROPERTY(getPropertyString("Node Filter"));
		istringstream iss(props);
		string token;
		vector<string> properties;
		while(getline(iss, token, ':')) {
			if(token.length()>0) {
				properties.push_back(token);
			}
		}
		if(listener) listener->setProgress(0);

		ofstream outp(file.c_str());
		if(!outp.is_open()) {
			error("Cannot open file %s\n", file.c_str());
			return;
		} 
		
		bool printedHeader = false;
		ElementIterator *it = graph->createNodeIterator();
		int i = 0;
		int n = graph->numNodes();
		for(it->begin();it->hasMoreElements();) {
      if(listener) listener->setProgress((float) i/(float) n);
			Node *node = (Node*) it->next();
			string line = "";
			string lineHeader = "";
			string lineHeaderType = "";
			bool passFilter = graph->getAsBoolean(node, filterProperty);
			if(!passFilter) continue;
			for(unsigned j=0;j<properties.size();j++) {
				if(properties[j]=="Default") continue;
				int type = node->getPropertyType(properties[j]);
				string sValue = node->getAsString(properties[j]);
				if(!printedHeader) {
					string sType = "STRING";
					if(type==PROPERTY_FLOAT) sType = "FLOAT";
					if(type==PROPERTY_SIGNED) sType = "SIGNED";
					if(type==PROPERTY_INT) sType = "INT";
					if(type==PROPERTY_STRING) sType = "STRING";
					lineHeaderType = lineHeaderType + sType;
					lineHeader = lineHeader + properties[j];
					if(j<properties.size()-1) {
						lineHeaderType += "\t";
						lineHeader += "\t";
					}
				}
				line = line +  sValue;
				if(j<properties.size()-1) {
					line += "\t";
				}
			}
			if(!printedHeader) {
				outp << lineHeaderType << endl;
				outp << lineHeader << endl;
				printedHeader = true;
			}
			outp << line << endl;
			i++;
		}
		outp.close();
		graph->destroyIterator(it);
		
		if(listener) listener->done();
	}
};


void addDataTools(Controller *controller) {
	controller->addTool(new ExportEdgeTool(controller));
	controller->addTool(new ExportTool(controller));
}